package com.springboot.file.util.easyexcel.strategy;

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 表头自动合并处理器
 * 自动合并相同内容的表头单元格
 */
public class HorizontalCellMergeStrategy implements SheetWriteHandler {

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        // 创建前不做处理
    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        Sheet sheet = writeSheetHolder.getSheet();
        
        // 获取表头行数
        int headerRowCount = getHeaderRowCount(sheet);
        
        // 对每个表头行进行处理
        for (int rowIndex = 0; rowIndex < headerRowCount; rowIndex++) {
            processHeaderRow(sheet, rowIndex);
        }
    }
    
    /**
     * 获取表头行数
     * 
     * @param sheet Excel表单
     * @return 表头行数
     */
    private int getHeaderRowCount(Sheet sheet) {
        int headerRowCount = 0;
        
        for (int i = 0; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null || !isHeaderRow(row)) {
                break;
            }
            headerRowCount++;
        }
        
        return headerRowCount;
    }
    
    /**
     * 处理单个表头行的合并
     * 
     * @param sheet Excel表单
     * @param rowIndex 行索引
     */
    private void processHeaderRow(Sheet sheet, int rowIndex) {
        Row row = sheet.getRow(rowIndex);
        if (row == null) {
            return;
        }
        
        // 获取需要合并的单元格范围列表
        List<CellRangeAddress> mergeRanges = getMergeRangesForRow(row, rowIndex);
        
        // 应用合并
        applyMerges(sheet, mergeRanges);
    }
    
    /**
     * 获取行中需要合并的单元格范围
     * 
     * @param row 表头行
     * @param rowIndex 行索引
     * @return 合并范围列表
     */
    private List<CellRangeAddress> getMergeRangesForRow(Row row, int rowIndex) {
        // 记录每个表头内容在当前行首次出现的位置
        Map<String, Integer> valuePositionMap = new HashMap<>();
        
        // 记录当前行需要合并的单元格区域
        List<CellRangeAddress> mergeRanges = new ArrayList<>();
        
        // 处理行中的每个单元格
        processCellsInRow(row, rowIndex, valuePositionMap, mergeRanges);
        
        return mergeRanges;
    }
    
    /**
     * 处理行中的所有单元格，找出需要合并的范围
     * 
     * @param row 表头行
     * @param rowIndex 行索引
     * @param valuePositionMap 值位置映射
     * @param mergeRanges 合并范围列表
     */
    private void processCellsInRow(Row row, int rowIndex, 
                                 Map<String, Integer> valuePositionMap,
                                 List<CellRangeAddress> mergeRanges) {
        int lastCellNum = row.getLastCellNum();
        
        for (int colIndex = 0; colIndex < lastCellNum; colIndex++) {
            Cell cell = row.getCell(colIndex);
            
            // 获取有效的单元格值
            String cellValue = getValidCellValue(cell);
            if (cellValue == null) {
                continue;
            }
            
            // 处理单个单元格
            processSingleCell(colIndex, cellValue, rowIndex, valuePositionMap, mergeRanges);
        }
    }
    
    /**
     * 获取有效的单元格值，如果单元格为空或值为空则返回null
     * 
     * @param cell 单元格
     * @return 有效的单元格值或null
     */
    private String getValidCellValue(Cell cell) {
        if (cell == null) {
            return null;
        }
        
        String cellValue = getCellStringValue(cell);
        return cellValue.isEmpty() ? null : cellValue;
    }
    
    /**
     * 处理单个单元格，确定是否需要合并
     * 
     * @param colIndex 列索引
     * @param cellValue 单元格值
     * @param rowIndex 行索引
     * @param valuePositionMap 值位置映射
     * @param mergeRanges 合并范围列表
     */
    private void processSingleCell(int colIndex, String cellValue, int rowIndex,
                                 Map<String, Integer> valuePositionMap,
                                 List<CellRangeAddress> mergeRanges) {
        // 检查这个值是否已经在前面的列出现过
        if (valuePositionMap.containsKey(cellValue)) {
            int firstPosition = valuePositionMap.get(cellValue);
            
            // 检查是否可以合并
            if (canMergeWithPrevious(colIndex, firstPosition, mergeRanges)) {
                updateMergeRanges(colIndex, firstPosition, rowIndex, mergeRanges);
            }
        } else {
            // 记录该值首次出现的位置
            valuePositionMap.put(cellValue, colIndex);
        }
    }
    
    /**
     * 检查当前单元格是否可以与之前的单元格合并
     * 
     * @param colIndex 当前列索引
     * @param firstPosition 相同值首次出现的位置
     * @param mergeRanges 已有的合并范围
     * @return 是否可以合并
     */
    private boolean canMergeWithPrevious(int colIndex, int firstPosition, 
                                       List<CellRangeAddress> mergeRanges) {
        // 如果相邻，可以合并
        if (colIndex == firstPosition + 1) {
            return true;
        }
        
        // 如果首次位置已在某个合并区域内，也可以合并
        return mergeRanges.stream().anyMatch(range -> 
                range.getFirstColumn() <= firstPosition && 
                range.getLastColumn() >= firstPosition);
    }
    
    /**
     * 更新合并范围列表
     * 
     * @param colIndex 当前列索引
     * @param firstPosition 相同值首次出现的位置
     * @param rowIndex 行索引
     * @param mergeRanges 合并范围列表
     */
    private void updateMergeRanges(int colIndex, int firstPosition, int rowIndex, 
                                 List<CellRangeAddress> mergeRanges) {
        // 查找包含firstPosition的已有合并区域
        Optional<CellRangeAddress> existingRangeOpt = mergeRanges.stream()
                .filter(range -> range.getFirstColumn() <= firstPosition && 
                                range.getLastColumn() >= firstPosition)
                .findFirst();
        
        if (existingRangeOpt.isPresent()) {
            // 扩展现有合并区域
            CellRangeAddress existingRange = existingRangeOpt.get();
            mergeRanges.remove(existingRange);
            
            mergeRanges.add(new CellRangeAddress(
                    rowIndex, rowIndex,
                    existingRange.getFirstColumn(), colIndex
            ));
        } else {
            // 创建新的合并区域
            mergeRanges.add(new CellRangeAddress(
                    rowIndex, rowIndex,
                    firstPosition, colIndex
            ));
        }
    }
    
    /**
     * 应用所有合并区域到表单
     * 
     * @param sheet Excel表单
     * @param mergeRanges 合并范围列表
     */
    private void applyMerges(Sheet sheet, List<CellRangeAddress> mergeRanges) {
        // 过滤出有效的合并区域（起始列和结束列不同）
        List<CellRangeAddress> validMerges = mergeRanges.stream()
                .filter(range -> range.getFirstColumn() != range.getLastColumn())
                .collect(Collectors.toList());
        
        // 应用合并
        validMerges.forEach(sheet::addMergedRegion);
    }

    /**
     * 判断一行是否为表头行
     */
    private boolean isHeaderRow(Row row) {
        // 表头行通常格式化为粗体或不同的样式
        // 简单判断：如果行中的单元格都不是数字类型，则可能是表头
        boolean isHeader = true;
        for (int i = 0; i < row.getLastCellNum(); i++) {
            Cell cell = row.getCell(i);
            if (cell != null && cell.getCellType() == CellType.NUMERIC) {
                isHeader = false;
                break;
            }
        }
        return isHeader;
    }

    /**
     * 获取单元格的字符串值
     */
    private String getCellStringValue(Cell cell) {
        if (cell == null) return "";

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                return String.valueOf(cell.getNumericCellValue());
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }
}